package cn.foxtech.cloud.repo.comp.model.service;


import cn.craccd.mongoHelper.bean.Page;
import cn.craccd.mongoHelper.bean.SortBuilder;
import cn.craccd.mongoHelper.utils.CriteriaAndWrapper;
import cn.craccd.mongoHelper.utils.CriteriaOrWrapper;
import cn.craccd.mongoHelper.utils.CriteriaWrapper;
import cn.foxtech.cloud.common.mongo.entity.EdgeEntity;
import cn.foxtech.cloud.common.utils.mongo.MongoExHelper;
import cn.foxtech.cloud.core.constant.Constant;
import cn.foxtech.cloud.core.exception.ServiceException;
import cn.foxtech.cloud.repo.comp.model.constants.ConstantRepoCompModel;
import cn.foxtech.cloud.repo.comp.model.constants.ConstantRepoCompModelObject;
import cn.foxtech.cloud.repo.comp.model.constants.ConstantRepoCompModelVersion;
import cn.foxtech.cloud.repo.comp.model.entity.RepoCompModelEntity;
import cn.foxtech.cloud.repo.comp.model.entity.RepoCompModelObjectEntity;
import cn.foxtech.cloud.repo.comp.model.entity.RepoCompModelVersionEntity;
import cn.foxtech.common.utils.method.MethodUtils;
import cn.foxtech.common.utils.security.SecurityUtils;
import cn.foxtech.common.utils.uuid.UuidUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;

import java.util.*;

@Component
public class RepoCompModelVersionService {
    @Autowired
    private MongoExHelper mongoHelper;

    @Autowired
    private RepoCompModelObjectService objectService;

    @Autowired
    private RepoCompModelService modelService;


    public void initialize() {
        List<String> indexFields = new ArrayList<>();

        // 创建数据库表：如果不存在则创建，存在则跳过
        this.mongoHelper.createCollection(ConstantRepoCompModelVersion.field_collection_name, indexFields);
    }

    public void insertVersionEntity(RepoCompModelVersionEntity entity) {
        if (MethodUtils.hasEmpty(entity.getAuthor(), entity.getModelId(), entity.getObjects())) {
            throw new ServiceException("参数不能为空: modelId, author, objects");
        }

        // 验证：操作内容是否合法
        this.objectService.verifyEntityList(entity.getObjects());

        // 写入数据库
        this.mongoHelper.insert(ConstantRepoCompModelVersion.field_collection_name, entity);
    }

    /**
     * 上传版本
     *
     * @param userName
     * @param body
     */
    public RepoCompModelVersionEntity uploadVersionEntity(String userName, Map<String, Object> body) {
        String compId = (String) body.get(ConstantRepoCompModelVersion.field_comp_id);
        String description = (String) body.get(ConstantRepoCompModelVersion.field_description);
        String commitKey = (String) body.get(ConstantRepoCompModel.field_commit_key);
        List<Map<String, Object>> objects = (List<Map<String, Object>>) body.get(ConstantRepoCompModelVersion.field_objects);
        if (MethodUtils.hasEmpty(compId, objects)) {
            throw new ServiceException("body参数缺失: compId, objects");
        }

        // 独立提示
        if (MethodUtils.hasEmpty(commitKey)) {
            throw new ServiceException("请输入commitKey");
        }


        Map<String, Object> param = new HashMap<>();
        param.put(ConstantRepoCompModelVersion.field_id, compId);
        CriteriaWrapper criteriaWrapper = this.modelService.buildWrapper(param);
        List<RepoCompModelEntity> entityList = this.modelService.queryEntityList(criteriaWrapper);
        if (entityList.isEmpty()) {
            throw new ServiceException("找不到对应的组件!");
        }


        RepoCompModelEntity modelEntity = entityList.get(0);
        if (!userName.equals("admin")) {
            if (commitKey.isEmpty()) {
                throw new ServiceException("只有下列人员才可以提交：admin和持有commitKey的人员：" + modelEntity.getGroupName());
            }

            // 验证提交密码
            if (!SecurityUtils.matchesPassword(commitKey, modelEntity.getCommitKey())) {
                throw new ServiceException("commitKey验证不通过！");
            }
        }


        // 构造一个新版本对象
        RepoCompModelVersionEntity newEntity = this.buildVersionEntity(userName, modelEntity.getId(), objects, description);

        // 检查：是否缺少最小参数
        if (MethodUtils.hasEmpty(newEntity.getAuthor(), newEntity.getModelId(), newEntity.getObjects())) {
            throw new ServiceException("参数不能为空: modelId, author, objects");
        }

        // 查找最近的提交版本
        param = new HashMap<>();
        param.put(ConstantRepoCompModelVersion.field_model_id, modelEntity.getId());
        criteriaWrapper = this.buildWrapper(param);
        RepoCompModelVersionEntity lastEntity = this.queryEntity(criteriaWrapper, new SortBuilder(RepoCompModelEntity::getCreateTime, Sort.Direction.DESC));
        if (lastEntity == null) {
            // 插入脚本代码
            this.insertVersionEntity(newEntity);
            return newEntity;
        }

        // 比较一下，内容是否发生了变化
        String lastValue = this.getServiceValue(lastEntity.getObjects());
        String newValue = this.getServiceValue(newEntity.getObjects());
        if (!lastValue.equals(newValue)) {
            this.insertVersionEntity(newEntity);
            return newEntity;
        }


        throw new ServiceException("没有发生修改，请勿重复提交!");
    }

    public RepoCompModelVersionEntity buildVersionEntity(String userName, String modelId, List<Map<String, Object>> objects, String description) {
        RepoCompModelVersionEntity entity = new RepoCompModelVersionEntity();
        entity.setModelId(modelId);
        entity.setAuthor(userName);
        entity.setDescription(description);

        for (Map<String, Object> operate : objects) {
            String modelName = (String) operate.get(ConstantRepoCompModelObject.field_model_name);
            Map<String, Object> modelParam = (Map<String, Object>) operate.get(ConstantRepoCompModelObject.field_model_param);
            Map<String, Object> extendParam = (Map<String, Object>) operate.get(ConstantRepoCompModelObject.field_extend_param);
            Object updateTime = operate.get(ConstantRepoCompModelObject.field_update_time);
            Object createTime = operate.get(ConstantRepoCompModelObject.field_create_time);

            // 简单校验参数
            if (MethodUtils.hasEmpty(modelName, modelParam, updateTime, createTime)) {
                throw new ServiceException("参数不能为空: modelName, modelParam, updateTime, createTime");
            }
            if (MethodUtils.hasNull(extendParam)) {
                throw new ServiceException("参数不能为空: extendParam");
            }

            RepoCompModelObjectEntity objectEntity = new RepoCompModelObjectEntity();
            objectEntity.setObjectId(UuidUtils.randomUUID());
            objectEntity.setModelName(modelName);
            objectEntity.setModelParam(modelParam);
            objectEntity.setExtendParam(extendParam);
            objectEntity.setCreateTime(Long.parseLong(createTime.toString()));
            objectEntity.setUpdateTime(Long.parseLong(updateTime.toString()));

            entity.getObjects().add(objectEntity);
        }

        return entity;
    }

    private String getServiceValue(List<RepoCompModelObjectEntity> list) {
        list.sort(new Comparator<RepoCompModelObjectEntity>() {
            @Override
            public int compare(RepoCompModelObjectEntity v1, RepoCompModelObjectEntity v2) {
                String name1 = v1.getModelName();
                String name2 = v2.getModelName();
                return name1.compareTo(name2);
            }
        });

        StringBuilder sb = new StringBuilder();
        for (RepoCompModelObjectEntity entity : list) {
            sb.append(entity.makeServiceValue());
            sb.append(";");
        }

        return sb.toString();
    }

    public RepoCompModelVersionEntity queryVersionEntity(String id) {
        return this.mongoHelper.findById(id, ConstantRepoCompModelVersion.field_collection_name, RepoCompModelVersionEntity.class);
    }

    public void deleteVersionEntity(List<String> ids) {
        this.mongoHelper.deleteByIds(ids, ConstantRepoCompModelVersion.field_collection_name, RepoCompModelVersionEntity.class);
    }

    public List<RepoCompModelVersionEntity> queryEntityList(CriteriaWrapper criteriaWrapper) {
        SortBuilder sortBuilder = new SortBuilder(RepoCompModelEntity::getCreateTime, Sort.Direction.DESC);
        List<RepoCompModelVersionEntity> result = this.mongoHelper.findListByQuery(criteriaWrapper, sortBuilder, ConstantRepoCompModelVersion.field_collection_name, RepoCompModelVersionEntity.class);
        return result;
    }

    public RepoCompModelVersionEntity queryEntity(CriteriaWrapper criteriaWrapper, SortBuilder sortBuilder) {
        RepoCompModelVersionEntity result = this.mongoHelper.findOneByQuery(criteriaWrapper, sortBuilder, ConstantRepoCompModelVersion.field_collection_name, RepoCompModelVersionEntity.class);
        return result;
    }


    public CriteriaAndWrapper buildWrapper(Map<String, Object> param) {
        CriteriaAndWrapper andWrapper = new CriteriaAndWrapper();
        if (param.containsKey(ConstantRepoCompModelVersion.field_id)) {
            andWrapper.eq(ConstantRepoCompModelVersion.field_id, param.get(ConstantRepoCompModelVersion.field_id));
        }
        if (param.containsKey(ConstantRepoCompModelVersion.field_author)) {
            andWrapper.eq(ConstantRepoCompModelVersion.field_author, param.get(ConstantRepoCompModelVersion.field_author));
        }
        if (param.containsKey(ConstantRepoCompModelVersion.field_model_id)) {
            andWrapper.eq(ConstantRepoCompModelVersion.field_model_id, param.get(ConstantRepoCompModelVersion.field_model_id));
        }
        if (param.containsKey(ConstantRepoCompModelVersion.field_model_ids)) {
            andWrapper.in(ConstantRepoCompModelVersion.field_model_id, (Collection) param.get(ConstantRepoCompModelVersion.field_model_ids));
        }
        if (param.containsKey(ConstantRepoCompModelVersion.field_description)) {
            andWrapper.like(ConstantRepoCompModelVersion.field_description, (String) param.get(ConstantRepoCompModelVersion.field_description));
        }

        // 关键词查询：从这些文本字段中查询
        if (param.containsKey(ConstantRepoCompModelVersion.field_keyword)) {
            CriteriaOrWrapper orWrapper = new CriteriaOrWrapper();
            orWrapper.like(ConstantRepoCompModelVersion.field_author, (String) param.get(ConstantRepoCompModelVersion.field_keyword));
            orWrapper.like(ConstantRepoCompModelVersion.field_description, (String) param.get(ConstantRepoCompModelVersion.field_keyword));

            andWrapper.and(orWrapper);
        }

        return andWrapper;
    }

    public Map<String, Object> queryPageList(CriteriaWrapper criteriaWrapper, Map<String, Object> body) {
        Integer pageNum = (Integer) body.get(Constant.field_page_num);
        Integer pageSize = (Integer) body.get(Constant.field_page_size);

        // 检查：是否至少包含以下几个参数
        if (MethodUtils.hasEmpty(pageNum, pageSize)) {
            throw new ServiceException("body参数缺失: pageNum, pageSize");
        }

        // 分页查询
        Page<EdgeEntity> page = new Page<>();
        page.setQueryCount(true);
        page.setCurr(pageNum);
        page.setLimit(pageSize);
        SortBuilder sortBuilder = new SortBuilder(RepoCompModelVersionEntity::getCreateTime, Sort.Direction.DESC);
        Page<RepoCompModelVersionEntity> result = this.mongoHelper.findPage(criteriaWrapper, sortBuilder, page, ConstantRepoCompModelVersion.field_collection_name, RepoCompModelVersionEntity.class);

        // 将结果返回
        Map<String, Object> data = new HashMap<>();
        data.put("total", result.getCount());
        data.put("list", result.getList());


        return data;
    }
}
